{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "aa7fe030",
   "metadata": {},
   "source": [
    "# 💼 AskMyCV - Minimal Notebook Version\n",
    "An intelligent CV chatbot that answers questions about a professional's career, skills, and experience using their resume.\n",
    "\n",
    "---\n",
    "\n",
    "**Live Demo:** [https://lisekarimi.com]\n",
    "\n",
    "- 📋 Overview\n",
    "    - 🌍 **Task:** Intelligent CV/resume question answering\n",
    "    - 🧠 **Model:** OpenAI GPT-4o-mini\n",
    "    - 🎯 **Process:** Load PDF/Summary → OpenAI SDK Agentic AI → Answer\n",
    "    - 📌 **Output Format:** Conversational responses via Gradio interface\n",
    "    - 🔧 **Tools:** OpenAI SDK (Agentic AI), PyPDF, Gradio, Pushover\n",
    "    - 🧑‍💻 **Skill Level:** Advanced\n",
    "\n",
    "- 🛠️ Requirements\n",
    "    - ⚙️ **Hardware:** ✅ CPU is sufficient\n",
    "    - 🔑 **OpenAI API Key**\n",
    "    - 🔔 **Pushover credentials** (for notifications)\n",
    "        - PUSHOVER_USER=_put the key that's on the top right of your Pushover home screen and probably starts with a u_  \n",
    "        - PUSHOVER_TOKEN=_put the key when you click into your new application called AskMyCV (or whatever) and probably starts with an a_\n",
    "    - Create a `data/` folder in this directory and add the following files:\n",
    "        - `linkedin.pdf` - Your LinkedIn profile export\n",
    "        - `summary.txt` - Your summary text file\n",
    "---\n",
    "📢 Discover more Agentic AI notebooks on my [GitHub repository](https://github.com/lisekarimi/agentverse) and explore additional AI projects on my [portfolio](https://lisekarimi.com).\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d7b18176",
   "metadata": {},
   "source": [
    "## 1. 📦 Imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e8e13a42",
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import load_dotenv\n",
    "import os\n",
    "import requests\n",
    "from pypdf import PdfReader\n",
    "import gradio as gr\n",
    "from pathlib import Path\n",
    "\n",
    "# Set environment variable BEFORE importing agents\n",
    "os.environ['OPENAI_AGENTS_DISABLE_TRACING'] = '1'\n",
    "\n",
    "from agents import Agent, Runner, function_tool"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "83ed7f0a",
   "metadata": {},
   "source": [
    "## 2. ⚙️ Setup"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c1ea5177",
   "metadata": {},
   "outputs": [],
   "source": [
    "load_dotenv(override=True)\n",
    "MODEL = \"gpt-4o-mini\"\n",
    "\n",
    "# Pushover setup\n",
    "pushover_user = os.getenv(\"PUSHOVER_USER\")\n",
    "pushover_token = os.getenv(\"PUSHOVER_TOKEN\")\n",
    "pushover_url = \"https://api.pushover.net/1/messages.json\"\n",
    "\n",
    "print(f\"Pushover user: {'found ✓' if pushover_user else 'not found ✗'}\")\n",
    "print(f\"Pushover token: {'found ✓' if pushover_token else 'not found ✗'}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8f9556e5",
   "metadata": {},
   "source": [
    "## 3. 🔧 Tool functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "de63c11b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def push(message):\n",
    "    print(f\"Push: {message}\")\n",
    "    payload = {\"user\": pushover_user, \"token\": pushover_token, \"message\": message}\n",
    "    requests.post(pushover_url, data=payload)\n",
    "\n",
    "@function_tool\n",
    "def record_user_details(email: str, name: str = \"Name not provided\", notes: str = \"not provided\") -> dict:\n",
    "    \"\"\"Use this tool to record that a user is interested in being in touch and provided an email address.\n",
    "\n",
    "    Args:\n",
    "        email: The email address of this user\n",
    "        name: The user's name, if they provided it\n",
    "        notes: Any additional information about the conversation that's worth recording to give context\n",
    "    \"\"\"\n",
    "    push(f\"Recording interest from {name} with email {email} and notes {notes}\")\n",
    "    return {\"recorded\": \"ok\", \"email\": email, \"name\": name}\n",
    "\n",
    "@function_tool\n",
    "def record_unknown_question(question: str) -> dict:\n",
    "    \"\"\"Always use this tool to record any question that couldn't be answered.\n",
    "\n",
    "    Args:\n",
    "        question: The question that couldn't be answered\n",
    "    \"\"\"\n",
    "    push(f\"Recording unknown question: {question}\")\n",
    "    return {\"recorded\": \"ok\", \"question\": question}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a2f2283",
   "metadata": {},
   "source": [
    "## 4. 📚 Load knowledge base"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e76b799b",
   "metadata": {},
   "outputs": [],
   "source": [
    "pdf_path = Path(\"data/linkedin.pdf\")\n",
    "summary_path = Path(\"data/summary.txt\")\n",
    "\n",
    "print(f\"Reading PDF from: {pdf_path}\")\n",
    "print(f\"Reading summary from: {summary_path}\")\n",
    "\n",
    "# Load the LinkedIn PDF\n",
    "reader = PdfReader(str(pdf_path))\n",
    "linkedin = \"\"\n",
    "for page in reader.pages:\n",
    "    text = page.extract_text()\n",
    "    if text:\n",
    "        linkedin += text\n",
    "\n",
    "# Load the summary\n",
    "with open(summary_path, \"r\", encoding=\"utf-8\") as f:\n",
    "    summary = f.read()\n",
    "\n",
    "name = \"Lise Karimi\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "330499d7",
   "metadata": {},
   "source": [
    "## 6. 🤖 Create the Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94873d80",
   "metadata": {},
   "outputs": [],
   "source": [
    "career_instructions = f\"\"\"You are acting as {name}. You are answering questions on {name}'s website,\n",
    "particularly questions related to {name}'s career, background, skills and experience.\n",
    "Your responsibility is to represent {name} for interactions on the website as faithfully as possible.\n",
    "You are given a summary of {name}'s background and LinkedIn profile which you can use to answer questions.\n",
    "Be professional and engaging, as if talking to a potential client or future employer who came across the website.\n",
    "\n",
    "If you don't know the answer to any question, use your record_unknown_question tool to record the question that you couldn't answer, even if it's about something trivial or unrelated to career.\n",
    "\n",
    "If the user is engaging in discussion, try to steer them towards getting in touch via email; ask for their email and record it using your record_user_details tool.\n",
    "\n",
    "## Summary:\n",
    "{summary}\n",
    "\n",
    "## LinkedIn Profile:\n",
    "{linkedin}\n",
    "\n",
    "With this context, please chat with the user, always staying in character as {name}.\"\"\"\n",
    "\n",
    "career_agent = Agent(\n",
    "    name=\"Career Assistant\",\n",
    "    instructions=career_instructions,\n",
    "    model=MODEL,\n",
    "    tools=[record_user_details, record_unknown_question]\n",
    ")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4ca6b4c0",
   "metadata": {},
   "source": [
    "## 7. 💬 Chat function using agent Runner"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "63633eb1",
   "metadata": {},
   "outputs": [],
   "source": [
    "async def chat(message, history):\n",
    "    messages = []\n",
    "    for msg in history:\n",
    "        messages.append({\"role\": msg[\"role\"], \"content\": msg[\"content\"]})\n",
    "\n",
    "    messages.append({\"role\": \"user\", \"content\": message})\n",
    "\n",
    "    result = await Runner.run(career_agent, messages)\n",
    "\n",
    "    return result.final_output"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebe0bb16",
   "metadata": {},
   "source": [
    "## 8. 🚀 Launch Gradio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b510114f",
   "metadata": {},
   "outputs": [],
   "source": [
    "gr.ChatInterface(chat, type=\"messages\").launch()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}